﻿using System;
using Nexia.FluentHtmlElements.Elements;
using Nexia.FluentHtmlElements.Utilities;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;

namespace FluentHtmlElements.Tests.Elements
{
	public abstract class ElementBaseTagAttributeTestsBase<TTestSubject> : BaseFixture
		where TTestSubject : ElementBase<TTestSubject>, new()
	{
		public abstract AttributeTestInfo<TTestSubject> TestInfo
		{
			get;
		}

		[Test]
		public void Id_NullValue_SetAttrIsCalled()
		{
			TestStringAttribute_SetAttrIsCalled_Helper(
				TestInfo.ExpectedCall,
				TestInfo.MethodUnderTest,
				null
				);
		}

		[Test]
		public void Id_EmptyValue_SetAttrIsCalled()
		{
			TestStringAttribute_SetAttrIsCalled_Helper(
				TestInfo.ExpectedCall,
				TestInfo.MethodUnderTest,
				String.Empty
				);
		}

		[Test]
		public void Id_ValidValue_SetAttrIsCalled()
		{
			TestStringAttribute_SetAttrIsCalled_Helper(
				TestInfo.ExpectedCall,
				TestInfo.MethodUnderTest,
				"i love pie"
				);
		}

		[Test]
		public void Id_AnyCall_ReturnsSelf()
		{
			TestStringAttribute_AnyCall_ReturnsSelf(TestInfo.MethodUnderTest);
		}

		protected void TestStringAttribute_SetAttrIsCalled_Helper(Action<TTestSubject, string> expectedCall, Func<TTestSubject, string, TTestSubject> methodUnderTest, string value)
		{
			var tagBuilder = Stub<ITagBuilder>();

			var elementBase = Partial<TTestSubject>(tagBuilder);
			expectedCall(elementBase, value);

			ReplayAll();

			methodUnderTest(elementBase, value);

			VerifyAll();
		}

		protected void TestStringAttribute_AnyCall_ReturnsSelf(Func<TTestSubject, string, TTestSubject> methodUnderTest)
		{
			var tagBuilder = Stub<ITagBuilder>();

			var elementBase = new TTestSubject {Builder = tagBuilder};

			ReplayAll();

			var returnValue = methodUnderTest(elementBase, default(string));

			Assert.That(returnValue, Is.SameAs(elementBase));

			VerifyAll();
		}

		/// <summary>
		/// A stub who's ToString value can be set through a property.
		/// </summary>
		/// <remarks>This object is used because Rhino mocks doesn't seem to be able to do it.</remarks>
		protected class StubObject
		{
			public string ToStringValue;

			public override string ToString()
			{
				return ToStringValue;
			}
		}
	}
}
